﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Primitives;
using System.ComponentModel.Composition.ReflectionModel;
using System.Linq;
using System.Threading;

namespace Mefisto4.Core.MEF
{
    public class ControllerPartDefinitionDecorator : ComposablePartDefinition
    {
        private readonly ComposablePartDefinition _inner;
        private readonly Type _controllerType;
        private readonly string _controllerName;
        private readonly string _controllerNamespace;
        private readonly object _locker = new object();
        private IEnumerable<ExportDefinition> _redefinedExports;

        public ControllerPartDefinitionDecorator(ComposablePartDefinition inner, Type controllerType, string controllerName, string controllerNamespace)
        {
            _inner = inner;
            _controllerType = controllerType;
            _controllerName = controllerName;
            _controllerNamespace = controllerNamespace;
        }

        public override IEnumerable<ExportDefinition> ExportDefinitions
        {
            get
            {
                if (_redefinedExports == null)
                {
                    lock (_locker)
                    {
                        if (_redefinedExports == null)
                        {
                            var exports = _inner.ExportDefinitions;
                            var metadata = new Dictionary<string, object>();
                            metadata[typeof(CreationPolicy).FullName] = CreationPolicy.NonShared;
                            metadata[Constants.ControllerNameMetadataName] = _controllerName.Substring(0, _controllerName.Length - "Controller".Length);
                            metadata[Constants.ControllerNamespaceMetadataName] = _controllerNamespace;
                            metadata[Constants.ExportedTypeIdentityMetadataName] = Constants.ControllerTypeIdentity;
                            metadata[Constants.ControllerTypeMetadataName] = Constants.ControllerTypeIdentity;

                            var controllerExport = ReflectionModelServices.CreateExportDefinition(
                                new LazyMemberInfo(_controllerType),
                                Constants.ControllerContract,
                                new Lazy<IDictionary<string, object>>(() => metadata),
                                _inner as ICompositionElement);

                            Thread.MemoryBarrier();

                            _redefinedExports = exports.Union(new[] { controllerExport }).ToArray();
                        }
                    }
                }

                return _redefinedExports;
            }
        }

        public override IEnumerable<ImportDefinition> ImportDefinitions
        {
            get { return _inner.ImportDefinitions; }
        }

        public override ComposablePart CreatePart()
        {
            return _inner.CreatePart();
        }
    }
}